package com.atwisdom.star.core.bsl.planner.Impl;

import cn.hutool.core.collection.CollectionUtil;
import com.alibaba.fastjson.JSONObject;
import com.atwisdom.star.common.vo.ModelType;
import com.atwisdom.star.core.bsl.planner.ProductBomBslService;
import com.atwisdom.star.core.bsl.planner.entity.*;
import com.atwisdom.star.core.dao.pojo.modelClass.hier.HierInstance;
import com.atwisdom.star.core.dao.pojo.modelClass.staticLogic.StaticLogicInstance;
import com.atwisdom.star.core.dsl.modelClass.hier.HierInstanceDslService;
import com.atwisdom.star.core.dsl.modelClass.staticLogic.Impl.StaticLogicInstanceDslServiceImpl;
import com.atwisdom.star.exception.pojo.BusinessException;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

@Service
@Data
@NoArgsConstructor
public class ProductBomBslServiceImpl implements ProductBomBslService {
    @Autowired
    private StaticLogicInstanceDslServiceImpl staticLogicInstanceDslService;
    @Autowired
    private HierInstanceDslService hierInstanceDslService;
    @Autowired
    private MaterialBslServiceImpl materialBslService;
    //组合BOM信息
    private List<HierInstance> combinedHierInstances = new ArrayList<>();
    //拆分BOM信息
    private List<HierInstance> spitHierInstances = new ArrayList<>();
    //BOM对象列表
    private List<ProductBomMaster> productBomList = new ArrayList<>();
    //产品BOM层级列表
    private List<ProductBomLevel> productBomLevels = new ArrayList<>();

    @Autowired
    private MrpLogBslServiceImpl mrpLogBslService;

    /**
     * 初始化BOM信息
     */
    public void initBOM() {
        this.productBomList = new ArrayList<>();
        //组合BOM
        StaticLogicInstance staticLogicInstance = staticLogicInstanceDslService.fetchByClassName("CombinedBOM");
        this.combinedHierInstances = this.hierInstanceDslService.queryByContainerId(ModelType.StaticLogic.getCode(), staticLogicInstance.getClassName(), staticLogicInstance.getId());
        this.buildProductCombinedBom(this.combinedHierInstances, this.productBomList);
        //拆分BOM
        staticLogicInstance = staticLogicInstanceDslService.fetchByClassName("SplitBOM");
        this.spitHierInstances = this.hierInstanceDslService.queryByContainerId(ModelType.StaticLogic.getCode(), staticLogicInstance.getClassName(), staticLogicInstance.getId());
        this.buildProductSplitBom(this.spitHierInstances, this.productBomList);
    }

    public void initCombinedBom(String bcode) {
        this.productBomList = new ArrayList<>();
        StaticLogicInstance staticLogicInstance = staticLogicInstanceDslService.fetchByClassName("CombinedBOM");
        String hierCondition = " parentId = 'root' && material_bcode = '"+bcode+"'";
        List<HierInstance> topHierInstances = this.hierInstanceDslService.queryByContainerId(ModelType.StaticLogic.getCode(), staticLogicInstance.getId(), staticLogicInstance.getClassName(),hierCondition);
        if(CollectionUtil.isEmpty(topHierInstances)){
            throw new BusinessException("999999", String.format("背番：%s组合BOM没有维护，初始组合BOM失败！",bcode));
        }
        HierInstance bomHierInstance = topHierInstances.get(0);
        String nodeId = bomHierInstance.getNodeId();
        hierCondition = " (nodeId = '" + nodeId + "' or parentId = '" + nodeId + "')";
        this.combinedHierInstances = this.hierInstanceDslService.queryByContainerId(ModelType.StaticLogic.getCode(), staticLogicInstance.getId(), staticLogicInstance.getClassName(),hierCondition);
        this.buildProductCombinedBom(this.combinedHierInstances, this.productBomList);
    }

    public void initSplitBom(String bcode) {
        this.productBomList = new ArrayList<>();
        StaticLogicInstance staticLogicInstance = staticLogicInstanceDslService.fetchByClassName("SplitBOM");
        String hierCondition = " parentId != 'root' && material_bcode = '"+bcode+"'";
        List<HierInstance> subHierInstances = this.hierInstanceDslService.queryByContainerId(ModelType.StaticLogic.getCode(), staticLogicInstance.getId(), staticLogicInstance.getClassName(),hierCondition);
        if(CollectionUtil.isEmpty(subHierInstances)){
            throw new BusinessException("999999", String.format("背番：%拆分BOM没有维护，初始拆分BOM失败！",bcode));
        }
        HierInstance bomHierInstance = subHierInstances.get(0);
        String parentId = bomHierInstance.getParentId();
        hierCondition = " ( nodeId = '" + parentId + "' or parentId = '" + parentId + "' )";
        this.spitHierInstances = this.hierInstanceDslService.queryByContainerId(ModelType.StaticLogic.getCode(), staticLogicInstance.getId(), staticLogicInstance.getClassName(),hierCondition);
        this.buildProductSplitBom(this.spitHierInstances, this.productBomList);
    }

    private void buildProductCombinedBom(List<HierInstance> bomHierInstances, List<ProductBomMaster> pBomList) {
        List<HierInstance> hierInsList = bomHierInstances.stream().filter(d -> "root".equalsIgnoreCase(d.getParentId())).collect(Collectors.toList());
        hierInsList.forEach(hIns -> {
            JSONObject values = hIns.getValues();
            Boolean enable = values.getBoolean("enable");
            if (enable) {
                ProductBomMaster productBomMaster = new ProductBomMaster();
                productBomMaster.setBomCode(values.getString("bomCode"));
                productBomMaster.setMaterialPCode(values.getString("material_pcode"));
                productBomMaster.setMaterialBCode(values.getString("material_bcode"));
                productBomMaster.setMaterialName(values.getString("material_name"));
                productBomMaster.setMaterialUnit(values.getString("material_unit"));
                productBomMaster.setInvertWarehouse(values.getInteger("invertWarehouse"));
                productBomMaster.setInvertLocation(values.getInteger("invertLocation"));
                productBomMaster.setEnable(true);
                Double quantity = values.getDouble("quantity");
                productBomMaster.setQuantity(quantity == null ? 1.0 : quantity);
                Double lossRate = values.getDouble("lossRate");
                productBomMaster.setLossRate(lossRate == null ? 0.0 : lossRate/100);
                Double bomVersion = values.getDouble("bomVersion");
                bomVersion = bomVersion == null ? 1.0 : bomVersion;
                productBomMaster.setBomVersion(bomVersion);
                productBomMaster.setNodeId(hIns.getNodeId());
                productBomMaster.setParentId(hIns.getParentId());
                productBomMaster.setBomType(Constant.COMBINED_BOM);
                List<ProductBomSub> productBomSubs = this.buildProductBomSub(bomHierInstances, hIns.getNodeId());
                productBomMaster.setMaterialBomSubList(productBomSubs);
                pBomList.add(productBomMaster);
            }
        });
    }

    private void buildProductSplitBom(List<HierInstance> bomHierInstances, List<ProductBomMaster> pBomList) {
        List<HierInstance> hierInsList = bomHierInstances.stream().filter(d -> "root".equalsIgnoreCase(d.getParentId())).collect(Collectors.toList());
        hierInsList.forEach(hIns -> {
            JSONObject values = hIns.getValues();
            Boolean enable = values.getBoolean("enable");
            if (enable) {
                ProductBomSub materialBomSub = new ProductBomSub();
                String bomCode = values.getString("bomCode");
                materialBomSub.setBomCode(bomCode);
                materialBomSub.setMaterialPCode( values.getString("material_pcode"));
                materialBomSub.setMaterialBCode(values.getString("material_bcode"));
                materialBomSub.setMaterialName(values.getString("material_name"));
                materialBomSub.setMaterialUnit(values.getString("material_unit"));
                materialBomSub.setInvertWarehouse(values.getInteger("invertWarehouse"));
                materialBomSub.setInvertLocation(values.getInteger("invertLocation"));
                Double quantity = values.getDouble("quantity");
                materialBomSub.setQuantity(quantity == null ? 1.0 : quantity);
                Double lossRate = values.getDouble("lossRate");
                materialBomSub.setLossRate(lossRate == null ? 0.0 : lossRate/100);
                materialBomSub.setNodeId(hIns.getNodeId());
                materialBomSub.setParentId(hIns.getParentId());
                Double bomVersion = values.getDouble("bomVersion");
                List<ProductBomSub> productBomSubs = this.buildProductBomSub(bomHierInstances, hIns.getNodeId());
                for (ProductBomSub productBomSub:productBomSubs) {
                    if(productBomSub.getMaterialBCode().equalsIgnoreCase("B-T162-1")){
                        System.out.println(productBomSub.getMaterialBCode());
                    }
                    ProductBomMaster productBomMaster = new ProductBomMaster();
                    BeanUtils.copyProperties(productBomSub,productBomMaster);
                    productBomMaster.setBomCode(bomCode);
                    productBomMaster.setBomVersion(bomVersion==null?1.0:bomVersion);
                    productBomMaster.setEnable(true);
                    productBomMaster.setBomType(Constant.SPLIT_BOM);
                    List<ProductBomSub> productBomSubList = productBomSubs.stream().filter(p -> !p.getMaterialBCode().equalsIgnoreCase(productBomSub.getMaterialBCode())).collect(Collectors.toList());
                    productBomMaster.setProductBomSubList(productBomSubList);
                    List<ProductBomSub> materialBomSubList = new ArrayList<>();
                    materialBomSubList.add(materialBomSub);
                    productBomMaster.setMaterialBomSubList(materialBomSubList);
                    pBomList.add(productBomMaster);
                }
            }
        });
    }

    private List<ProductBomSub> buildProductBomSub(List<HierInstance> bomHierInstances, String parentId) {
        List<HierInstance> hierInsList = bomHierInstances.stream().filter(d -> d.getParentId().equalsIgnoreCase(parentId)).collect(Collectors.toList());
        List<ProductBomSub> productBomSubs = new ArrayList<>();
        hierInsList.forEach(hIns -> {
            JSONObject values = hIns.getValues();
            String nodeId = hIns.getNodeId();
            String materialBCode = values.getString("material_bcode");
            String materialName = values.getString("material_name");
            String materialPCode = values.getString("material_pcode");
            String materialUnit = values.getString("material_unit");
            Integer invertWarehouse = values.getInteger("invertWarehouse");
            Integer invertLocation = values.getInteger("invertLocation");
            Double quantity = values.getDouble("quantity");
            Double lossRate = values.getDouble("lossRate");
            String bomCode = values.getString("bomCode");
            String splitBomCode = values.getString("split_bomCode");
            ProductBomSub productBomSub = new ProductBomSub();
            productBomSub.setBomCode(bomCode);
            productBomSub.setMaterialPCode(materialPCode);
            productBomSub.setMaterialBCode(materialBCode);
            productBomSub.setMaterialName(materialName);
            productBomSub.setMaterialUnit(materialUnit);
            productBomSub.setInvertWarehouse(invertWarehouse);
            productBomSub.setInvertLocation(invertLocation);
            productBomSub.setQuantity(quantity == null ? 1.0 : quantity);
            productBomSub.setLossRate(lossRate == null ? 0.0 : lossRate/100);
            productBomSub.setNodeId(nodeId);
            productBomSub.setParentId(parentId);
            productBomSub.setSplitBomCode(splitBomCode);
            productBomSubs.add(productBomSub);
        });
        return productBomSubs;
    }

    public void buildProductBomLevel(String bCode) {
        this.productBomLevels = new ArrayList<>();
        ProductBomMaster productBomMaster = this.productBomList.stream().filter(pb -> bCode.equalsIgnoreCase(pb.getMaterialBCode())).findFirst().orElse(null);
        ProductBomLevel productBomLevel;
        int level = 0;
        double quantity = 1;
        if (productBomMaster == null) {
            productBomLevel = new ProductBomLevel(bCode, level, quantity, null,Arrays.asList(bCode), materialBslService.getMaterialAttrMap().get(bCode),0.0,null);
            productBomLevels.add(productBomLevel);
        } else {
            level++;
            if(productBomMaster.getQuantity()==null){
                productBomMaster.setQuantity(1.0);
            }
            quantity = productBomMaster.getQuantity();
            productBomLevel = new ProductBomLevel(bCode, level, quantity, null,Arrays.asList(bCode),this.materialBslService.getMaterialAttrMap().get(bCode),productBomMaster.getLossRate(),productBomMaster.getProductBomSubList());
            productBomLevels.add(productBomLevel);
            List<ProductBomSub> materialBomSubList = productBomMaster.getMaterialBomSubList();
            if (CollectionUtil.isNotEmpty(materialBomSubList)) {
                level++;
                for (ProductBomSub productBomSub : materialBomSubList) {
//                    String materialBCode = productBomSub.getMaterialBCode();
//                    List<String> parentBCodePath = productBomLevel.getParentBCodePath().stream().collect(Collectors.toList());
//                    if(parentBCodePath.contains(materialBCode)){
//                        String msg =String.format("背番（%s）子件不能在背番（%s）的母件或父母件中",materialBCode,bCode);
//                        this.mrpLogBslService.buildMrpLog(2, msg);
//                        throw new BusinessException("999999", msg);
//                    }
//                    parentBCodePath.add(materialBCode);
//                    productBomLevel = new ProductBomLevel(materialBCode, level, quantity, bCode,parentBCodePath,this.materialBslService.getMaterialAttrMap().get(materialBCode),productBomSub.getLossRate());
//                    productBomLevels.add(productBomLevel);
//                    buildChildProductBomLevel(materialBCode, productBomLevels);
                    dealProductBomLevel(bCode, productBomLevels, productBomSub, productBomLevel, level);
                }
            }
        }
    }

    public void buildChildProductBomLevel(String bCode, List<ProductBomLevel> productBomLevels) {
        ProductBomMaster productBomMaster = this.productBomList.stream().filter(pb -> bCode.equalsIgnoreCase(pb.getMaterialBCode())).findFirst().orElse(null);
        if (productBomMaster == null) {
            return;
        }
        ProductBomLevel productBomLevel = productBomLevels.stream().filter(pbl -> bCode.equalsIgnoreCase(pbl.getMaterialBCode())).findFirst().orElse(null);
        if (productBomLevel != null) {
            List<ProductBomSub> materialBomSubList = productBomMaster.getMaterialBomSubList();
            if (CollectionUtil.isNotEmpty(materialBomSubList)) {
                int level = productBomLevel.getLevel() + 1;
                for (ProductBomSub productBomSub : materialBomSubList) {
                    dealProductBomLevel(bCode, productBomLevels, productBomSub, productBomLevel, level);
                }
            }
        }
    }

    private void dealProductBomLevel(String bCode, List<ProductBomLevel> productBomLevels, ProductBomSub productBomSub, ProductBomLevel productBomLevel, int level) {
        String materialBCode = productBomSub.getMaterialBCode();
        List<String> parentBCodePath = productBomLevel.getParentBCodePath().stream().collect(Collectors.toList());
        if(parentBCodePath.contains(materialBCode)){
            String msg =String.format("子件（%s）不能作为母件（%s）的父母件，互为母件系统无法处理！",materialBCode, bCode);
            this.mrpLogBslService.buildMrpLog(2, msg);
            throw new BusinessException("999999", msg);
        }
        parentBCodePath.add(materialBCode);
        ProductBomMaster productBomMaster = this.productBomList.stream().filter(pb -> materialBCode.equalsIgnoreCase(pb.getMaterialBCode())).findFirst().orElse(null);
        List<ProductBomSub> productBomSubList;
        if(productBomMaster!=null){
            productBomSubList = productBomMaster.getProductBomSubList();
        }else{
            productBomSubList = null;
        }
        productBomLevel = new ProductBomLevel(materialBCode, level, productBomSub.getQuantity(), bCode,parentBCodePath,this.materialBslService.getMaterialAttrMap().get(materialBCode), productBomSub.getLossRate(),productBomSubList);
        productBomLevels.add(productBomLevel);
        buildChildProductBomLevel(materialBCode, productBomLevels);
    }


    /**
     * 检查产品的BOM 类型组合：combined ，拆分：split
     *
     * @return 返回BOM类型，组合：combined，拆分：split，无BOM：null
     */
    public String checkProductBomType(String bCode) {
        ProductBomMaster productBomMaster = this.productBomList.stream().filter(d -> bCode.equalsIgnoreCase(d.getMaterialBCode())).findFirst().orElse(null);
        if (productBomMaster != null) {
            return productBomMaster.getBomType();
        }
        return null;
    }

}
